#!/usr/bin/env python
# spyftp.py
# Copyright (C) WANG Cong, 2007

import getopt, sys, os
import ftplib,string

class myftp(object):
	def __init__(self):
		return	
	def ftpConnect(self, host):
		msg = ''
		global verbose
		global username, password
		try:
			self.f = ftplib.FTP(host)
			self.f.login(username, password)
		except:
			return -1
		else:
			msg = self.f.getwelcome()
			if verbose:
				print msg
		return 0
	def ftpSendCmd(self, cmds):
		msg = ''
		global verbose,connect
		global debug
		if cmds[0].upper() == 'LS':
			msg = self.f.retrlines("LIST "+msg.join(cmds[1:]))
		elif cmds[0].upper() == 'DIR':
			msg = self.f.retrlines("NLST "+msg.join(cmds[1:]))
		elif cmds[0].upper() == 'DELETE':
			msg = self.f.delete(msg.join(cmds[1:]))
		elif cmds[0].upper() == 'RMDIR':
			msg = self.f.rmd(msg.join(cmds[1:]))
		elif cmds[0].upper() == 'MKDIR':
			msg = self.f.mkd(msg.join(cmds[1:]))
		elif cmds[0].upper() == 'RENAME':
			if len(cmds) == 3:
				msg = self.f.rename(cmds[1],cmds[2])
			else:
				print 'rename needs 2 arguments!'
				print 'rename old_filename new_filename'
		elif cmds[0].upper() == 'CLOSE':
			msg = self.f.close()
			connect = 0
		elif cmds[0].upper() == 'SIZE':
			if len(cmds)==2: 
				 print self.f.size(cmds[1])
		elif cmds[0].upper() == 'QUOTE':
			if len(cmds) >= 2:
				self.f.sendcmd(string.join(cmds[1:]))  
			else:
				self.f.sendcmd(raw_input( '(command line to send) '))
		elif cmds[0].upper() == 'CHMOD':
			if len(cmds) >= 3:
				self.f.sendcmd('SITE CHMOD '+string.join(cmds[1:3]))  
			else:
				print 'chmod needs 2 arguments! '
				print 'chmod MODE filename'
		elif cmds[0].upper() == 'DEBUG':
		  	if debug: debug = 0
		  	else: debug = 1
			msg = self.f.debug(debug)

		elif cmds[0].upper() == 'CD':
			if len(cmds)==1:
				return 0
			try:
				msg = self.f.cwd(cmds[1])
			except:
				print "\tNo such directory."
				return -2
			else:
				print self.f.sendcmd('pwd')
		elif cmds[0].upper() == 'PWD':
			print self.f.sendcmd(cmds[0])
		elif cmds[0].upper() == 'PUT':
			if len(cmds)==2:
				try:
					self.file = open(cmds[1],"rb")
					msg = self.f.storbinary('STOR '+cmds[1], self.file)
				except:
					self.file.close()
					return -1
			elif len(cmds)==3:
				try:
					self.file = open(cmds[1],"rb")
					msg = self.f.storbinary('STOR '+cmds[2], self.file)
				except:
					self.file.close()
					return -1
			else:
				print "Bad usage of command put."
				return -2
			print "File transfered to server successfully."
			self.file.close()
		elif cmds[0].upper() == 'GET':
			if len(cmds)==2:
				try:
					self.file = open(cmds[1], "wb")
					msg = self.f.retrbinary('RETR '+cmds[1], procFile)
				except:
					self.file.close()
					return -1
			elif len(cmds)==3:
				try:
					self.file = open(cmds[2], "wb")
					msg = self.f.retrbinary('RETR '+cmds[1], procFile)
				except:
					self.file.close()
					return -1
			else:
				print "Bad usage of comand get"
				return -2
			print "File tranfered from server successfully."
			self.file.close()
		else:
			msg = self.f.sendcmd(msg.join(cmds))
		if verbose and msg=='':
			print msg	
		return 0

	def ftpClose(self):
		msg = 'Good bye!'
		global verbose
		self.f.close()
		if verbose:
			print msg

def procFile(s):
	global m
	m.file.write(s)
def usage():
	print sys.argv[0]+":",
	print '''
	[-h|--help] [-V|--version]
	[|-v|--verbose] [-u USER|--user=USER] [-p PASS| --pass=PASS] [host]'''
	return
def showVersion():
	print "0.1"
	return
def showCmds():
	print clientCmds;
	return
def showHelp():
	helpmessage = """
	cd      change remote working directory
	chmod   change file permissions of remote file
	close   terminate ftp session
	debug   oggle/set debugging mode
	delete  delete remote file
	dir     list contents of remote directory
	get     get a file
	help    print local help information
	lcd     change local working directory
	lcdup   get to local parent directory
	lcwd    change local working directory
	lls     list contents of local directory
	lpwd    print working directory on local machine
	ls      list contents of remote directory
	mkdir   make directory on the remote machine
	open    connect to remote ftp
	#passive turn passive transfer mode on/off
	put     send one file
	pwd     print working directory on remote machine
	quit    terminate ftp session and exit
	quote   send arbitrary ftp command
	rename  rename a file
	rmdir   remove directory on the remote machine
	size    show size of remote file
	status  show current status
	type    set file transfer type
	user    send new user information
	verbose toggle verbose mode"""
	print helpmessage
	return

def main():
	global verbose,debug,type,passive,connect
	global m
	global username, password
	if len(sys.argv) > 8:
		print "Bad usage!"
		print "\n"
		usage()
		return
	else:
		opts, args = getopt.getopt(sys.argv[1:], 
			"hvVu:p:", ["help", "verbose", "version", "user", "pass"])
		if len(args) > 1:
			print "Can't specify more hosts."
			return
		else:
			for o, a in opts: 
		    		if o in ("-h", "--help"): 
					usage()
					sys.exit()
				if o in ("-V","--version"):
					showVersion()
					sys.exit()
    				if o in ("-v", "--verbose"): 
        				verbose = 1
				if o in ("-u", "--user"):
					username = a
				if o in ("-p", "--pass"):
					password = a
		if len(args)==0:
			print "You didn't specify a host!"
			usage()
			sys.exit()
		host = args[0]
		print 'Connecting...'
		if 0!=m.ftpConnect(host):
			print "Connect failed!"
			sys.exit(-1)
		connect = 1
		print 'OK.'
		while 1:
			cmd = raw_input('Spyftp> ')
			cmds = cmd.split()
			if not cmds[0] in clientCmds:
				print "Wrong command: "+cmd+"."
				continue
			elif cmds[0].upper() == 'QUIT':
				break
			elif cmds[0].upper() == 'HELP':
				#showCmds()
				showHelp()
			elif cmds[0].upper() == 'VERBOSE':
				if verbose: verbose = 0
				else: verbose = 1
			elif cmds[0].upper() == 'TYPE':
				if len(cmds) != 2:
					print
		  		if cmds[1]=='ascii': type = 1
				else: type = 0
			elif cmds[0].upper() == 'STATUS':
				if connect==0: print 'Not Connected.'
				else: print 'Connected to %s'% host
				if verbose==1: print 'Verbose: on'
				else: print 'Verbose: off'
				if debug==1: print 'Debug: on'
				else: print 'Debug: off'
				if type==1: print 'Type: ascii'
				else: print 'Type: binary'
				if passive==1: print 'Passive: on'
				else: print 'Passive: off'
			elif cmds[0].upper() == 'USER':
				if len(cmds)==3:
					username=cmds[1]
					password=cmds[2]
			elif cmds[0].upper() == 'LCD':
				if len(cmds)==2: os.chdir(cmds[1])
				print 'cd into: ',os.getcwd()
			elif cmds[0].upper() == 'LPWD':
				print os.getcwd()
			elif cmds[0].upper() == 'LCDUP':
				os.chdir('..')
				print 'cd into: ',os.getcwd()
			elif cmds[0].upper() == 'LCWD':
				if len(cmds)==2: os.chdir(cmds[1])
			elif cmds[0].upper() == 'LLS':
				if len(cmds)==1: dir = '.'
				else: dir = cmds[1]
				for i in os.listdir(dir):
					print i
			elif connect == 0 or cmds[0].upper() == 'OPEN':
				host = cmds[1]
				print 'Connecting...'
				if 0!=m.ftpConnect(host):
					print "Connect failed!"
					sys.exit(-1)
				print 'OK.'
				connect = 1
			else:
				if -1==m.ftpSendCmd(cmds):
					print "Unexpected errors occurs."
	m.ftpClose()
	return

if __name__=='__main__':
	verbose = 0
	debug = 0
	connect = 0
	type = 0 #0 binary 1 ascii
	passive = 0
	username = "anonymous"
	password = "Spyftpuser@spyftp"
	m = myftp()
	ftpCmds_lower =  ['cd','pwd','get','put','ls','dir','delete','rmdir','mkdir','rename','close','open','size','quote','chmod','debug','verbose','type','status','user','lcd','lpwd','lls','lcdup''lcwd']
	clientCmds_lower = ftpCmds_lower + ['quit','help']
	clientCmds = [] 
	for i in clientCmds_lower:
		clientCmds.append(i.upper())

	clientCmds += clientCmds_lower
	#ftpCmds = ['cd','CD','pwd','PWD','get','GET','put','PUT','ls','LS','dir','DIR','delete','DELETE','rmdir','RMDIR','mkdir','MKDIR','rename','RENAME','close','CLOSE','open','OPEN','size','SIZE','quote','QUOTE','chmod','CHMOD','debug','DEBUG','verbose','VERBOSE','type','TYPE','status','STATUS','user','USER','lcd','LCD','lpwd','LPWD','lls','LLS','lcdup','LCDUP','lcwd','LCWD']
	#clientCmds = ftpCmds+['quit','QUIT','help','HELP']

	main()
